# coding:utf-8
# writingtime: 2022-7-30

import os
import datetime
from Data.randomData import RandomData
from Utilities.AutoGetOperator.selectPackage import get_func
from Utilities.AutoGetOperator.GetNmaeFunc.getOperatorClass import GetOperatorClass
from Utilities.Plot.SimplePlot import SimpleClass
from Operators.OperationOperators.Algebraic import A, GA, WA


class MultipleOperatorTestRandomData:
    def __init__(self, list_operator=[], getExpertWeight=None, getAttributeWeight=None,
                 scoreFunction=None, groupSize=None, imgShow=False, imgSaving=False,
                 q=3, x=2, a=2, b=2, *wast1, **waste2):
        '''
        function:测试多个算子对数据的聚合结果分析
        :param list_operator: 算子函数列表
        :param getExpertWeight: 专家权重计算方式
        :param getAttributeWeight: 属性权重计算方式
        :param scoreFunction: 得分函数
        :param groupSize: 决策群的维度，例如[a1,a2,a3]表示a1个专家，a2个方案，a3个属性
        :param imgShow: 控制是否展示图片
        :param imgSaving: 控制是否展示图片
        :param q: q
        :param x: 一个参数时用x
        :param a: 两个参数时用a，b
        :param b: 两个参数用a，b
        '''
        # 对于比较算子的初始化
        self.list_operator = []
        if len(list_operator) < 2:
            foundation_op = [A, WA, GA] + list_operator
            self.list_operator = foundation_op
        else:
            self.list_operator = list_operator
        # 对于数据群维度的初始化
        if groupSize is None:
            size = [4, 4, 4]

        else:
            size = groupSize
        # 初始化决策群
        x1, x2, x3 = size
        self.get_dataGroup=RandomData(expe_n=x1, plan_n=x2, attr_n=x3).get_Gaussian_random
        self.data_group = self.get_dataGroup()
        # 计算专家权重的类进行初始化
        if getExpertWeight is None:
            self.getExpertWeight = get_func(r'Utilities\GetWeight\getExpertWeight\GetSatisfactionWeight.py',
                                            'getSatisfactionWeight')
        else:
            self.getExpertWeight = getExpertWeight

        # 计算属性权重的类初始化
        if getAttributeWeight is None:
            self.getAttributeWeight = get_func(r'DecisionMethod\MABAC.py', 'MABAC')
        else:
            self.getAttributeWeight = getAttributeWeight

        # 得分函数的类初始化
        if scoreFunction is None:
            self.getScore = get_func(r'ScoreFunction\getS.py', 'getS')
        else:
            self.getScore = scoreFunction

        # 属性权重
        self.attribute_weight = []
        self.q = q
        self.x = x
        self.a = a
        self.b = b
        self.imgShow = imgShow
        self.imgSaving = False

    def set_dataGroup(self, data_group):
        '''
        function: 设置决策数据群
        :param data_group: 决策群
        :return:
        '''
        self.data_group = data_group

    def setExpertWeight(self, expert_weight):
        '''
        function: 设置专家权重
        :param weight_weight:专家权重
        :return:
        '''
        self.expert_weight = expert_weight

    def setAttributeWeight(self, attribute_weight):
        '''
        function: 设置属性权重
        :param attribute_weight: 属性权重
        :return:
        '''
        self.attribute_weight = attribute_weight

    def set_q(self, q):
        '''
        function: 对q的值进行修改
        :param q:
        :return:
        '''
        self.q = q

    def set_x(self, x):
        '''
        function: 对x的值进行修改
        :param x:
        :return:
        '''
        self.x = x

    def set_a(self, a):
        '''
        function: 对a的值进行修改
        :param a:
        :return:
        '''
        self.a = a

    def set_b(self, b):
        '''
        function: 对b的值进行修改
        :param b:
        :return:
        '''
        self.b = b

    def matrixReverse(self, matrix):
        '''
        function: 功能函数
        :param matrix: 矩阵
        :return: 行列交换的矩阵
        '''
        newMatrix = []
        for x in range(len(matrix[0])):
            temp = []
            for y in range(len(matrix)):
                temp.append(matrix[y][x])
            newMatrix.append(temp)

        return newMatrix

    def arrge(self, operator, expertWeight=[], attr_weight=[]):
        '''
        function: 对决策群进行集结
        :return:
        '''
        # 设置q的值
        # 对于设置专家权重的判断
        if len(expertWeight):
            pass
        else:
            self.setExpertWeight(expertWeight)

        aggre_matrix_1 = []  # 存放运算结果
        '''集结矩阵'''
        for i in range(len(self.data_group[0])):
            li_1 = []
            for j in range(len(self.data_group[0][0])):
                li_1.append(
                    operator([self.data_group[k][i][j] for k in range(len(self.data_group))], self.expert_weight,
                             self.q).getResult())
            aggre_matrix_1.append(li_1)
        if len(attr_weight):
            attr_weight = attr_weight

        else:
            # 属性权重,对于属性进行分析，因此需要翻转
            attr_weight = self.getAttributeWeight(self.matrixReverse(aggre_matrix_1),
                                                  [1 / len(aggre_matrix_1) for i in range(len(aggre_matrix_1))],
                                                  self.q).getResult()
        # 最终结果
        fianl_vlaue = [operator(i, attr_weight, self.q).getResult() for i in aggre_matrix_1]

        return fianl_vlaue

    def saveData(self, fname='1.txt', data_group=[], expertWeight=[], atttributeWeight=[], q_range=[]):
        '''
        function: 存储数据
        :param data_group: 决策群
        :param expertWeight: 专家权重
        :param atttributeWeight: 属性权重
        :param q:
        :return:
        '''

        # 写入data数据
        try:
            # data_file = open(fname, "w")
            # data_file.write("q:\n" + str(q_range) + "\n" +
            #                 "data set:\n" + str(data_group) + "\n" +
            #                 "expert weight:\n" + str(expertWeight) + "\n"
            #                                                          "attribute weight:\n" + str(
            #     atttributeWeight) + "\n")
            print(fname + " is saved")
            # data_file.close()
        except:
            print(fname + " fail")
        # 存储数据

    def OpsAnalyze(self,q_max=None):
        '''
        function: 对于多个算子对比分析
        :return:
        '''
        # 创建文件夹
        root_path = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
        result_path = os.path.join(root_path, r'Result\multipleOperatorTestRandomData')
        result_path = os.path.join(result_path, self.get_dataGroup.__name__)
        path = os.path.join(result_path, datetime.datetime.now().strftime('%Y-%m-%d'))
        fpath = os.path.join(path, r'img')
        tpath = os.path.join(path, r'data')
        try:
            os.makedirs(fpath)  # 图片存储地址
            os.makedirs(tpath)  # 数据存储地址
        except:
            print('folder already exists')

        # 对q的上限进行初始化
        if q_max is None:
            q_range = 12
        else:
            q_range = q_max
        length = len(self.list_operator)
        data_group = []
        name_list = []
        # print(self.list_operator,len(self.list_operator))
        for i in range(length):
            temp_list = []
            for j in range(3, q_range):
                self.set_q(j)
                temp = self.arrge(self.list_operator[i])
                temp_list.append([self.getScore(temp[k], self.q).getScore() for k in range(len(temp))])
            data_group.append(self.matrixReverse(temp_list))
            name_list.append(self.list_operator[i].__name__)
        tname = os.path.join(tpath, 'result.txt')
        self.saveData(tname, self.data_group, self.expert_weight, self.attribute_weight,
                      [3 + i for i in range(q_range - 3)])
        SimpleClass().opSensitivity(data_group, [3 + i for i in range(q_range - 3)], name_list,
                                    filename=fpath, imgSaving=self.imgSaving, imgShow=self.imgShow)


if __name__ == '__main__':
    """输入的list_operator中含有一个算子，默认与经典的A, WA, GA进行比较"""
    operation_path = GetOperatorClass('Einstein').getOperatorPath()
    EinsteinWA = get_func(operation_path['Einstein'], 'EinsteinWA')
    MultipleOperatorTestRandomData([EinsteinWA],imgShow=True, imgSaving=False).OpsAnalyze()
    """输入的list_operator中有多个算子"""
    # operator_operations = GetOperatorClass('Einstein').getOperatorAllOperations()
    # op_list = operator_operations['Einstein']
    # MultipleOperatorTestRandomData(op_list, imgShow=True, imgSaving=False).OpsAnalyze()
